#!/usr/bin/env python
# _*_ coding:utf-8 _*_
#
# @Version : 1.0
# @Time    : 2018年09月28日15:50:05
# @Author  : yuanweixin
# @File    : report.py
#
# ui测试报告脚本

import io
import os
import time
import platform
from base64 import b64encode
from jinja2 import Template, escape
from httprunner import logger
from httprunner.compat import basestring, bytes, json, numeric_types
from collections import Iterable
from datetime import datetime

from UiManager import separator
from UiManager.models import ReportInfo


def add_test_reports(runner, html_report_name=None):
    """
    定时任务或者异步执行报告信息落地
    :param html_report_name: str: 报告名称，为空默认时间戳命名
    :param runner: dict: runner
    :return:
    """
    time_stamp = int(runner.summary["time"]["start_at"])
    runner.summary['time']['start_datetime'] = datetime.fromtimestamp(time_stamp).strftime('%Y-%m-%d %H:%M:%S')
    html_report_name = html_report_name if html_report_name else runner.summary['time']['start_datetime']
    runner.summary['html_report_name'] = html_report_name
    report_path = runner.gen_html_report(html_report_template=os.path.join(os.getcwd(), "templates{}extent_report_template.html".format(separator)), html_report_name=html_report_name)

    kwargs = {
        'html_report_name': html_report_name,
        'status': runner.summary.get('success'),
        'successes': runner.summary.get('stat').get('successes'),
        'testsRun': runner.summary.get('stat').get('testsRun'),
        'start_at': runner.summary['time']['start_datetime'],
        'failures': int(runner.summary.get('stat').get('testsRun')) - int(runner.summary.get('stat').get('successes')),
        'percent':  int(runner.summary.get('stat').get('successes')) / int(runner.summary.get('stat').get('testsRun')) * 100,
        'report_path': html_report_name + '-' + runner.summary['time']['start_datetime'] + '.html'
    }

    ReportInfo.objects.create(**kwargs)
    return report_path


def render_html_report(summary, html_report_name=None, html_report_template=None):
    """ render html report with specified report name and template
        if html_report_name is not specified, use current datetime
        if html_report_template is not specified, use default report template
    """
    if not html_report_template:
        html_report_template = os.path.join(
            os.path.abspath(os.path.dirname(__file__)),
            "templates",
            "default_report_template.html"
        )
        logger.log_debug("No html report template specified, use default.")
    else:
        logger.log_info("render with html report template: {}".format(html_report_template))

    logger.log_info("Start to render Html report ...")
    logger.log_debug("render data: {}".format(summary))

    report_dir_path = os.path.join(os.getcwd(), "templates/reports")
    start_at_timestamp = int(summary["time"]["start_at"])
    summary["time"]["start_datetime"] = datetime.fromtimestamp(start_at_timestamp).strftime('%Y-%m-%d %H:%M:%S')
    if html_report_name:
        report_dir_path = os.path.join(report_dir_path, html_report_name)
        html_report_name += "-{}.html".format(summary["time"]["start_datetime"])
    else:
        html_report_name = "{}.html".format(summary["time"]["start_datetime"])

    if not os.path.isdir(report_dir_path):
        os.makedirs(report_dir_path)

    for index, suite_summary in enumerate(summary["details"]):
        if not suite_summary.get("name"):
            suite_summary["name"] = "test suite {}".format(index)
        for record in suite_summary.get("records"):
            meta_data = record['meta_data']
            stringify_data(meta_data, 'request')
            stringify_data(meta_data, 'response')

    with io.open(html_report_template, "r", encoding='utf-8') as fp_r:
        template_content = fp_r.read()
        report_path = os.path.join(report_dir_path, html_report_name)
        with io.open(report_path, 'w', encoding='utf-8') as fp_w:
            rendered_content = Template(template_content).render(summary)
            fp_w.write(rendered_content)

    logger.log_info("Generated Html report: {}".format(report_path))

    return report_path


def stringify_data(meta_data, request_or_response):
    headers = meta_data[request_or_response]["headers"]

    request_or_response_dict = meta_data[request_or_response]

    for key, value in request_or_response_dict.items():

        if isinstance(value, list):
            value = json.dumps(value, indent=2, ensure_ascii=False)

        elif isinstance(value, bytes):
            try:
                encoding = meta_data["response"].get("encoding")
                if not encoding or encoding == "None":
                    encoding = "utf-8"

                content_type = meta_data["response"]["content_type"]
                if "image" in content_type:
                    meta_data["response"]["content_type"] = "image"
                    value = "data:{};base64,{}".format(
                        content_type,
                        b64encode(value).decode(encoding)
                    )
                else:
                    value = escape(value.decode(encoding))
            except UnicodeDecodeError:
                pass

        elif not isinstance(value, (basestring, numeric_types, Iterable)):
            # class instance, e.g. MultipartEncoder()
            value = repr(value)

        meta_data[request_or_response][key] = value


def get_summary(result, start_at):
    """ get summary from test result
    """
    summary = {
        "success": result.wasSuccessful(),
        "stat": {
            'testsRun': result.testsRun,
            'failures': len(result.failures),
            'errors': len(result.errors),
            'skipped': len(result.skipped),
            'expectedFailures': len(result.expectedFailures),
            'unexpectedSuccesses': len(result.unexpectedSuccesses)
        }
    }
    summary["stat"]["successes"] = summary["stat"]["testsRun"] \
        - summary["stat"]["failures"] \
        - summary["stat"]["errors"] \
        - summary["stat"]["skipped"] \
        - summary["stat"]["expectedFailures"] \
        - summary["stat"]["unexpectedSuccesses"]

    if getattr(result, "records", None):
        summary["time"] = {
            'start_at': result.start_at,
            'duration': result.duration
        }
        summary["records"] = result.records
    else:
        summary["time"] = {
            'start_at': start_at,
            'duration': int(time.time()) - int(start_at)
        }
        summary["records"] = []

    return summary


def get_platform():
    return {
        "uirunner_version": '1.0',
        "python_version": "{} {}".format(
            platform.python_implementation(),
            platform.python_version()
        ),
        "platform": platform.platform()
    }


def timestamp_to_datetime(summary, type=True):
    if not type:
        time_stamp = int(summary["time"]["start_at"])
        summary['time']['start_datetime'] = datetime.datetime. \
            fromtimestamp(time_stamp).strftime('%Y-%m-%d %H:%M:%S')

    for detail in summary['details']:
        try:
            time_stamp = int(detail['time']['start_at'])
            detail['time']['start_at'] = datetime.datetime.fromtimestamp(time_stamp).strftime('%Y-%m-%d %H:%M:%S')
        except Exception:
            pass

        for record in detail['records']:
            try:
                time_stamp = int(record['meta_data']['request']['start_timestamp'])
                record['meta_data']['request']['start_timestamp'] = \
                    datetime.fromtimestamp(time_stamp).strftime('%Y-%m-%d %H:%M:%S')
            except Exception:
                pass
    return summary
